﻿using System;
using System.Collections.Generic;
using System.Text;

namespace VMExplorer
{
  class MemoryAddress : IComparable
	{
		#region Private fields

		private IntPtr _pointer;

		#endregion
		#region Public static constants

		public static readonly MemoryAddress Invalid = new MemoryAddress((IntPtr)(-1));
		public static readonly MemoryAddress Null = new MemoryAddress (IntPtr.Zero);

		#endregion
		#region Constructors

		public MemoryAddress (IntPtr address)
		{
			_pointer = address;
		}
		public MemoryAddress (int page)
		{
			_pointer = (IntPtr)(page * 4096);
		}

		#endregion
		#region Implicit casts

		public static implicit operator IntPtr (MemoryAddress ma) 
		{ 
			return ma._pointer; 
		}

    public static implicit operator MemoryAddress(IntPtr a)
    {
      return new MemoryAddress (a);
		}

		#endregion
		#region Public Properties

		public bool IsUserSpace { get { return _pointer.ToInt32 () >= 0; } }
		public bool IsNull { get { return _pointer == IntPtr.Zero; } }
		public bool IsValid { get { return _pointer.ToInt32 () > 0; } }

    public MemoryAddress LowerPageAligned { get { return new MemoryAddress (this.Page); } }
    public MemoryAddress UpperPageAligned { get { return new MemoryAddress (this.Page + 1); } }

		public int LowerPageOffset { get { return this._pointer.ToInt32 () - LowerPageAligned._pointer.ToInt32 (); } }
		public int UpperPageOffset { get { return UpperPageAligned._pointer.ToInt32 () - this._pointer.ToInt32 (); } }

    public int Page
    {
      get
      {
        if (this == Invalid)
        {
          return -1;
        }

				return _pointer.ToInt32 () / 4096;
      }
		}

		#endregion
		#region Object overrides

		public override string ToString ()
		{
			return "0x" + _pointer.ToString ("X8");
		}

		public override bool Equals (object obj)
		{
			MemoryAddress ma = obj as MemoryAddress;
			return (ma!=null) && (this==ma);
		}

		public override int GetHashCode ()
		{
			return _pointer.GetHashCode ();
		}

		#endregion
		#region Operators overloads

		// overload operator ==
    public static bool operator == (MemoryAddress a, MemoryAddress b)
    {
			return a._pointer == b._pointer;
    }
    // overload operator ==
    public static bool operator != (MemoryAddress a, MemoryAddress b)
    {
			return a._pointer != b._pointer;
		}

		// overload operator +
    public static MemoryAddress operator + (MemoryAddress a, MemoryAddress b)
    {
			return new MemoryAddress ((IntPtr)(a._pointer.ToInt32 () + b._pointer.ToInt32 ()));
    }
    public static MemoryAddress operator + (MemoryAddress a, Int32 b)
    {
			return new MemoryAddress ((IntPtr)(a._pointer.ToInt32 () + b));
    }
    public static MemoryAddress operator + (MemoryAddress a, UInt32 b)
    {
			return new MemoryAddress ((IntPtr)(a._pointer.ToInt32 () + b));
    }

    // overload operator -
    public static MemoryAddress operator - (MemoryAddress a, MemoryAddress b)
    {
			return new MemoryAddress ((IntPtr)(a._pointer.ToInt32 () - b._pointer.ToInt32 ()));
    }
    public static MemoryAddress operator - (MemoryAddress a, Int32 b)
    {
			return new MemoryAddress ((IntPtr)(a._pointer.ToInt32 () - b));
    }
    public static MemoryAddress operator - (MemoryAddress a, UInt32 b)
    {
			return new MemoryAddress ((IntPtr)(a._pointer.ToInt32 () - b));
    }

    // overload compare operators
    public static bool operator < (MemoryAddress a, MemoryAddress b)
    {
			return a._pointer.ToInt32 () < b._pointer.ToInt32 ();
    }
    public static bool operator > (MemoryAddress a, MemoryAddress b)
    {
			return a._pointer.ToInt32 () > b._pointer.ToInt32 ();
    }
    public static bool operator <= (MemoryAddress a, MemoryAddress b)
    {
			return a._pointer.ToInt32 () <= b._pointer.ToInt32 ();
    }
    public static bool operator >= (MemoryAddress a, MemoryAddress b)
    {
			return a._pointer.ToInt32 () >= b._pointer.ToInt32 ();
		}

		#endregion
    #region IComparable Members

    public int CompareTo(object obj)
    {
      MemoryAddress ma = obj as MemoryAddress;
      if(obj == null) throw new NotImplementedException();
      int x = this._pointer.ToInt32();
      int y = ma._pointer.ToInt32();
      return x.CompareTo(y);
    }

    #endregion
  }
}
